package java_thinking.unit_21._21_7;

import java.io.PrintWriter;
import java.io.Writer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @Desc:   7-13 不支持关闭的生产者-消费者日志服务 不要这么做
 *          1.不要这么做原因 见 L：51
 * @author: cww
 * @DateTime: 2019-06-16 14:47
 */

public class LogWriter {
    private final BlockingQueue<String> queue;
    private final LoggerThread logger;
    private static final int CAPACITY = 1000;

    public LogWriter(Writer writer) {
        this.queue = new LinkedBlockingDeque<>(1000);
        this.logger = new LoggerThread(writer);
    }

    public void start() {
        logger.start();
    }

    /**
     * 如果生产速度高于消费模式，这里put会阻塞
     * @param msg
     * @throws InterruptedException
     */
    public void log(String msg) throws InterruptedException {
        queue.put(msg);
    }

    private class LoggerThread extends Thread {
        private final PrintWriter writer;

        public LoggerThread(Writer writer) {
            //自动 flush
            this.writer = new PrintWriter(writer, true);
        }

        @Override
        public void run() {
            try {
                while (true) {
                    /**
                     * take能响应中断，当捕捉到 InterruptedException 时线程会退出，但是直接退出
                     * 日志线程时一种不完备的关闭机制，这样会丢失正在等待被写入到日志的信息，不仅如此，
                     * 其他线程将在调用log时被阻塞，因为日志消息队列是满的，因此这些线程将无法解除阻塞状态
                     * 所以在取消一个生产者-消费者操作时需要同时取消生产者和消费者
                     */
                    writer.println(queue.take());
                }
            } catch (InterruptedException e) {

            } finally {
                //关闭 LoggerThread 线程
                writer.close();
            }
        }
    }
}

